package dbsucxentW.pathProcessorW;

import java.sql.*;

public class SimpleXPathTranslator {
	private Connection dbconnection = null;

	private final String tabber = "   ";

	private boolean hasStar = false;

	private boolean isAttribute = false;

	private String _XPath = "";

	private String _FullXPath = "";

	private String _dbXPath = "";

	/** Creates a new instance of SimpleXPathTranslator */
	public SimpleXPathTranslator(Connection dbCon, String XPath) {
		dbconnection = dbCon;
		if (XPath.contains("*"))
			hasStar = true;

		_FullXPath = XPath;

		// Replace attribute() with @*
		// eg: /a/b/attribute() -> /a/b/@*
		if (XPath.endsWith("attribute()")) {
			XPath = XPath.replace("attribute()", "@*");
		}
		// Replace attribute::* with @*
		// eg: /a/b/attribute::* -> /a/b/@*
		if (XPath.endsWith("attribute::*")) {
			XPath = XPath.replace("attribute::*", "@*");
		}

		if (XPath.contains("@")) {
			if (XPath.contains("//")) {
				_XPath = XPath.substring(0, XPath.indexOf("@") - 1);
				_dbXPath = _XPath.replace("//", "#.%#.").replace("/", "#.")
						.replace("*", "%").substring(1)
						+ "#";
				isAttribute = true;
			} else {
				_XPath = XPath.substring(0, XPath.indexOf("@") - 1);
				_dbXPath = _XPath.replace("/", "#.").replace("*", "%")
						.substring(1)
						+ "#";
				isAttribute = true;
			}
		} else if (XPath.contains("//")) {
			_XPath = XPath;
			_dbXPath = _XPath.replace("//", "#%.").replace("/", "#.")
					.replace("*", "%").substring(1)
					+ "#";
		} else {
			_XPath = XPath;
			_dbXPath = _XPath.replace("/", "#.").replace("*", "%").substring(1)
					+ "#";
		}

		System.out.println("Input XPath: " + _FullXPath);
		System.out.println("DB XPath   : " + _dbXPath);
	}

	public String getTranslatedSQL(boolean _showPath) {

		String _StartWITH = "WITH V (LeafValue, PathID, BranchOrder, DeweyOrderSum, DocId, LeafOrder ) AS ( ";
		String _ORDERBY = "ORDER BY DocId, DeweyOrderSum, Attr, AttrOrder ";
		String _OPTION = "";
		String _EndWITH = ") ";
		String _SELECT1 = "SELECT V.*, 1 as Attr, 0 as AttrOrder ";
		String _FROM1 = "FROM V ";
		String _SELECT2 = "SELECT A.leafValue, A.pathID, V.branchOrder, V.DeweyOrderSum, A.DocId, A.LeafOrder, 0 as Attr, A.AttrOrder ";
		String _FROM2 = "FROM Attribute A, V ";
		String _WHERE2 = "WHERE A.DocId = V.DocId AND A.LeafOrder = V.LeafOrder \n"
				+ tabber + " AND A.PathID IN (#PathIDList#) ";
		String _SELECT = "SELECT V1.LeafValue, V1.PathID, V1.BranchOrder, "
				+ "V1.DeweyOrderSum, V1.DocId,  V1.LeafOrder ";
		String _FROM = "FROM PathValue V1 ";
		String _WHERE = "WHERE V1.PathID IN (#PathIDList#) ";

		boolean isElementPathExist = false;
		boolean isAttributePathExist = false;
		String ElementPathIDList = "", AttributePathIDList = "";
		try {
			Statement statement = dbconnection.createStatement();

			ResultSet results = statement
					.executeQuery("SELECT pathid, pathexp FROM PATH WHERE PATHEXP LIKE '"
							+ _dbXPath + "%' AND PATHEXP NOT LIKE '%@%'");

			boolean first = true;
			while (results.next()) {
				if (first) {
					if (hasStar) {
						if (isXPathValid(_XPath, results.getString("pathexp")
								.trim())) {
							ElementPathIDList += results.getString("Pathid");
							first = false;
							isElementPathExist = true;
						}
					} else {
						ElementPathIDList += results.getString("Pathid");
						first = false;
						isElementPathExist = true;
					}
				} else {
					if (hasStar) {
						if (isXPathValid(_XPath, results.getString("pathexp")
								.trim())) {
							ElementPathIDList += ","
									+ results.getString("Pathid");
						}
					} else {
						ElementPathIDList += "," + results.getString("Pathid");
					}
				}
			}
			_WHERE = _WHERE.replace("#PathIDList#", ElementPathIDList);

			// get attribute
			if (isAttribute) {
				if (_FullXPath.contains("//")) {
					_dbXPath = _FullXPath.replace("//", "#.%#.").replace("/",
							"#.").replace("*", "%").substring(1)
							+ "#";
				} else {

					_dbXPath = _FullXPath.replace("/", "#.").replace("*", "%")
							.substring(1)
							+ "#";
				}
				results = statement
						.executeQuery("SELECT pathid, pathexp FROM PATH WHERE PATHEXP LIKE '"
								+ _dbXPath + "%' AND PATHEXP LIKE '%@%'");
			} else {
				results = statement
						.executeQuery("SELECT pathid, pathexp FROM PATH WHERE PATHEXP LIKE '"
								+ _dbXPath + "%' AND PATHEXP LIKE '%@%'");
			}

			first = true;

			while (results.next()) {
				if (first) {
					if (hasStar) {
						if (isXPathValid(_XPath, results.getString("pathexp")
								.trim())) {
							AttributePathIDList = results.getString("Pathid");
							first = false;
							isAttributePathExist = true;
						}
					} else {
						AttributePathIDList = results.getString("Pathid");
						first = false;
						isAttributePathExist = true;
					}
				} else {
					if (hasStar) {
						if (isXPathValid(_XPath, results.getString("pathexp")
								.trim())) {
							AttributePathIDList += ","
									+ results.getString("Pathid");
						}
					} else {
						AttributePathIDList += ","
								+ results.getString("Pathid");
					}
				}
			}

			_WHERE2 = _WHERE2.replace("#PathIDList#", AttributePathIDList);

			results.close();
			statement.close();

		} catch (Exception ex) {
			System.out.println(ex.getMessage());
			// JOptionPane.showMessageDialog(null,ex.getMessage(), "Error",
			// JOptionPane.ERROR_MESSAGE);
			return "ERROR";
		}

		if (isAttribute && !isAttributePathExist) {
			return "ERROR";
		}
		else
		if (isElementPathExist && isAttributePathExist) {
			String query = "";
			if (isAttribute) {
				query = _StartWITH + "\n" +  tabber + _SELECT + "\n" + tabber
						+ _FROM + "\n" + tabber + _WHERE + "\n" + _EndWITH + " "
						+ _SELECT2 + "\n" + _FROM2 + "\n" + _WHERE2 + "\n"
						+ _ORDERBY + "\nOPTION (FORCE ORDER) \n";
			} else {
				query = _StartWITH + "\n" + tabber + _SELECT + "\n" + tabber
						+ _FROM + "\n" + tabber + _WHERE + "\n" + _EndWITH + " "
						+ _SELECT1 + "\n" + _FROM1 + "\n" + "UNION ALL \n"
						+ _SELECT2 + "\n" + _FROM2 + "\n" + _WHERE2 + "\n"
						+ _ORDERBY + "\nOPTION (FORCE ORDER) \n";
			}
			return query;
		} else if (isElementPathExist && !isAttributePathExist) {
			return _SELECT + "\n" + _FROM + "\n" + _WHERE + "\n"
					+ "ORDER BY DocId, DeweyOrderSum \n";
		} else {
			return "ERROR";
		}
	}

	public boolean isXPathValid(String pattern, String xpath) {
		String[] STemp = xpath.split("\\.");
		String[] PTemp = pattern.split("/");
		int i = 0;
		if (STemp.length >= PTemp.length) {
			boolean isOK = true;
			for (int x = 1; x < PTemp.length; x++) {
				if ((x >= PTemp.length) || ((x + i) >= STemp.length)) {
					isOK = false;
					break;
				}
				if (PTemp[x].equals("*")) {
					continue;
				} else if (PTemp[x].equals("@*")) {
					continue;
				} else if (PTemp[x].length() == 0) {
					if (STemp[x + i].equals(PTemp[x + 1] + "#")) {
						i--;
						x++;
						continue;
					}
					i++;
					if (STemp.length <= (x + i)) {
						isOK = false;
						break;
					}
					x--;
					continue;
				} else if (!STemp[x + i].equals(PTemp[x] + "#")) {
					isOK = false;
					break;
				}
			}
			if (isOK) {
				return true;
			}
		}
		return false;
	}
}
